using Abp;
using Abp.Authorization;
using Abp.Collections.Extensions;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Extensions;
using Abp.Json;
using Abp.Runtime.Session;
using Abp.Timing;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using Mt.Site.Core.Base.Domain.Entities.ShortId;
using Mt.Site.Core.Base.Reflection;
using Mt.Site.Core.ContentManagement.Entities;
using Mt.Site.Core.ContentManagement.Permissions;
using Mt.Site.Core.ContentManagement.Values;
using Mt.Site.Core.DataLogs;
using Mt.Site.Core.DiyContent.Form;
using Mt.Site.Core.DiyContent.Form.Entities;
using Mt.Site.Core.Navigations;
using Mt.Site.Core.Navigations.Enums;
using Mt.Site.Core.Navigations.Permissions;
using Mt.Site.Core.Navigations.Route;
using Mt.Site.Core.SEO;
using Mt.Site.Core.StaticPages;
using Mt.Site.Core.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Mt.Site.Core.ContentManagement.Impl
{
    // TODO: 一条内容在A栏目创建，被B栏目引用，如果A栏目要移除改信息，B栏目保留该信息，则存在转移的可能
    //   考虑以一个特定 的 转移操作来 实现，而不在编辑里实现
    //   即 包含、共享(呈送)（方式：信息链接，信息引用，信息实体）  ,转移
    /*
1.   呈送信息实体 是完整地复制一条新的信息，原源数据之间完全独立，二者间不会有任何关系标记
2.   呈送信息链接和呈送信息引用则会 在信息列表页上有标记， 源数据会标记呈送去向，目标数据在标题前有”链“或”引“的标记，同时会标记呈送来源。
3.   呈送信息链接和呈送信息引用的区别是，呈送信息打开详情页后，链接没有保存，预览等操作按钮，而引用可以编辑信息，因为和源数据是同一条数据，所以它的改动会影响源数据。

     */
    public class Content2Manager : MtSiteDomainServiceBase, IContent2Manager, ITransientDependency
    {
        private readonly IRepository<Content, Guid> _contentRepository;
        private readonly IRepository<Content2, Guid> _content2Repository;
        private readonly IRepository<ContentBody, long> _contentBodyRepository;
        private readonly IRepository<ContentField, long> _contentFieldRepository;

        private readonly IRepository<ContentMenu, Guid> _contentMenuRepository;

        private readonly IRouteStore _routeManager;
        private readonly IStaticPageHelper _staticPageHelper;
        private readonly IRepository<Seo, Guid> _seoRepository;
        private readonly IFileObjectManager _fileObjectManager;
        private readonly IMenuStore _menuStore;
        private readonly IDataLogsManager _dataLogsManager;

        internal readonly static string[] _specialFields = new string[] {
            "Id","TenantId","MenuId" ,"Language","AuxiliaryId","RelateId","Key", "Hit",
            "IsDeleted" ,"DeleterUserId"  ,"DeletionTime", "LastModificationTime",  "LastModifierUserId",  "CreationTime" ,"CreatorUserId" ,"AutoSynchronous",
            "ManagementType"
        };

        private readonly IPermissionChecker _permissionChecker;

        private readonly IMenuContentHelper _menuContentHelper;

        private readonly IUnitOfWorkManager _unitOfWorkManager;

        private readonly IShortIdManager _shortIdManager;

        public IAbpSession AbpSession { get; set; }

        public Content2Manager(
            IRepository<Content, Guid> contentRepository,
            IRepository<Content2, Guid> content2Repository,
            IRepository<ContentBody, long> contentBodyRepository,
            IRepository<ContentField, long> contentFieldRepository,
            IRepository<ContentMenu, Guid> contentMenuRepository,
            IRouteStore routeManager,
            IStaticPageHelper staticPageHelper,
            IRepository<Seo, Guid> seoRepository,
            IFileObjectManager fileObjectManager,
            IMenuStore menustore,
            IDataLogsManager dataLogsManager,
            IPermissionChecker permissionChecker,
            IMenuContentHelper menuContentHelper,
            IUnitOfWorkManager unitOfWorkManager,
            IShortIdManager shortIdManager)
        {
            _contentRepository = contentRepository;
            _content2Repository = content2Repository;
            _contentBodyRepository = contentBodyRepository;
            _contentFieldRepository = contentFieldRepository;
            _contentMenuRepository = contentMenuRepository;

            _routeManager = routeManager;
            _staticPageHelper = staticPageHelper;
            _seoRepository = seoRepository;
            _fileObjectManager = fileObjectManager;
            _menuStore = menustore;
            _dataLogsManager = dataLogsManager;
            _permissionChecker = permissionChecker;

            _menuContentHelper = menuContentHelper;
            _unitOfWorkManager = unitOfWorkManager;
            _shortIdManager = shortIdManager;

            AbpSession = NullAbpSession.Instance;
        }

        #region 获取配置数据

        public async Task<ContentConfig> GetConfig(string customKey, long menuId)
        {
            return await _menuContentHelper.GetConfig(customKey, menuId);
        }

        public async Task<string> GetCustomKey(string customKey, long menuId)
        {
            return await _menuContentHelper.GetCustomKey(customKey, menuId);
        }

        #endregion


        public async Task<Dictionary<string, object>> GetContentForEdit(Guid? id, long menuId, string customKey, Guid? relateId)
        {
            var result = new Dictionary<string, object>();

            customKey = await GetCustomKey(customKey, menuId);
            var config = await GetConfig(customKey, menuId);

            //依据配置返回
            if (id == null)
            {
                var detailFields = config.Detail
                    .Where(ContentFieldsHelper.CheckDataPredicate())
                    .ToList();

                foreach (var propertie in detailFields)
                {
                    var defaultValue = TypeHelper.GetDefaultValue(propertie.FieldType, propertie.DefaultValue);
                    result.Add(propertie.FieldName.ToCamelCase(), defaultValue);
                }

                result["order"] = await GetMaxOrderNumber(menuId, relateId);
                result["publishTime"] = DateTime.Now.ToUnixTimeByMilliseconds();
                result["key"] = customKey;
                result["menuId"] = menuId;
                result["relateId"] = relateId;
                result["routeStr"] = "";
                result["autoSynchronous"] = true;
                result["managementType"] = ManagementType.Manage;
            }
            else
            {
                var query = from cm in _contentMenuRepository.GetAll()
                            join c in _content2Repository.GetAll()
                            on cm.ContentId equals c.Id
                            where c.Id == id.Value && cm.MenuId == menuId && cm.RelateId == relateId
                            select new Content2TempData
                            {
                               Content= c,
                               ContentMenu = cm 
                            };
                var temp = await query.FirstOrDefaultAsync();
                if (temp != null)
                {
                    var content = temp.Content;

                    // 可能是其他不同类型的数据从别的栏目分享而来
                    if(content.Key != customKey && config.ProhibitAdding)
                    {
                        config = await _menuContentHelper.GetConfig(content.Key);
                    }
                    var detailFields = config.Detail
                        .Where(ContentFieldsHelper.CheckDataPredicate())
                        .ToList();

                    var bodyFields = await _contentBodyRepository.GetAllListAsync(c => c.ContentId == content.Id);
                    var fields = await _contentFieldRepository.GetAllListAsync(c => c.ContentId == content.Id);
                    bool hasAdded;

                    foreach (var propertie in detailFields)
                    {
                        hasAdded = false;
                        var propertieKey = propertie.FieldName.ToPascalCase();
                        var value = TypeHelper.GetPropertyValue(content, propertieKey);
                        if (value != null)
                        {
                            hasAdded = true;
                            result.Add(propertieKey.ToCamelCase(), value);
                        }
                        else
                        {
                            ContentBody item = null;
                            if (bodyFields != null)
                            {
                                item = bodyFields.FirstOrDefault(c => c.FieldName == propertieKey);
                                if (item != null)
                                {
                                    hasAdded = true;
                                    result.Add(propertieKey.ToCamelCase(), item.Value);
                                }
                            }
                            if (item == null && fields != null)
                            {
                                var item2 = fields.FirstOrDefault(c => c.FieldName == propertieKey);
                                if (item2 != null)
                                {
                                    hasAdded = true;
                                    result.Add(propertieKey.ToCamelCase(), item2.Value);
                                }
                            }
                        }
                        if (!hasAdded) //正常不会出现
                        {
                            var defaultValue = TypeHelper.GetDefaultValue(propertie.FieldType, propertie.DefaultValue);
                            result[propertieKey.ToCamelCase()] = defaultValue;
                        }
                    }

                    foreach (var propertieKey in _specialFields)
                    {
                        var value = TypeHelper.GetPropertyValue(content, propertieKey);
                        result[propertieKey.ToCamelCase()] = value;
                    }
                    //result["routeStr"] = await _routeManager.GetRouteStrFromDbAndFormatAsync(temp.ContentMenu.Id, content.TenantId);
                    result["order"] = temp.ContentMenu.Order;
                    result["publishTime"] = temp.ContentMenu.PublishTime;
                    result["managementType"] = temp.ContentMenu.ManagementType;
                }
                else
                {
                    throw new UserFriendlyException("未找到该数据");
                }
            }


            return result;
        }

        public async Task<Guid> CreateAsync(Dictionary<string, string> values, long menuId, string customKey, Guid? relateId)
        {
            _permissionChecker.IsMenuIdPermissionGrantedOrThrowException(menuId, LocalizationSource);

            var content = new Content2() { Id = Guid.NewGuid() };

            customKey = await GetCustomKey(customKey, menuId);


            var config = await GetConfig(customKey, menuId);
            var bodyFields_New = new List<NameValue>();
            var fields_New = new List<NameValue>();
            Mapping(values, content, config, bodyFields_New, fields_New);

            content.MenuId = menuId;
            content.Key = customKey;
            content.RelateId = relateId;

            if (content.PublishTime == 0)
            {
                content.PublishTime = Clock.Now.ToUnixTimeByMilliseconds();
            }

            await _content2Repository.InsertAsync(content);
            var contentMenuId = Guid.NewGuid();
            await _contentMenuRepository.InsertAsync(new ContentMenu
            {
                Id = contentMenuId,
                MenuId = menuId,
                EntityTypeName = content.GetType().Name,
                ContentId = content.Id,
                ManagementType = ManagementType.Manage,
                Order = content.Order,
                PublishTime = content.PublishTime,
                RelateId = relateId
            }) ;

            foreach (var item in bodyFields_New)
            {
                var body = new ContentBody { ContentId = content.Id, FieldName = item.Name, Value = item.Value };
                await _contentBodyRepository.InsertAsync(body);
            }
            foreach (var item in fields_New)
            {
                var body = new ContentField { ContentId = content.Id, FieldName = item.Name, Value = item.Value };
                await _contentFieldRepository.InsertAsync(body);
            }

            long relateIdLong = 0;
            if (relateId != null)
            {
                relateIdLong = await GetAuxiliaryIdAsync(relateId.Value);
            }

            if (MtSiteConsts2.BackgroundJobs)
            {
                _staticPageHelper.DeleteListPage(content.TenantId, content.Language, content.MenuId);
                _staticPageHelper.DeleteStaticPage(content.TenantId, content.Language, 0); //首页
            }

            var optionType = content.IsActive ? DataLogOptionType.CreateAndPublish : DataLogOptionType.Create;
            await _dataLogsManager.CreateAsync(content, menuId, optionType);

            await CurrentUnitOfWork.SaveChangesAsync();

            await SetRouteStr(values, contentMenuId, menuId, relateIdLong, content, config, true);

            return content.Id;
        }


        public async Task<Guid> UpdateAsync(Dictionary<string, string> values, Guid contentId, long menuId, string customKey, Guid? relateId)
        {
            //修改时要更新ContentMenu 表中的发布时间， 如果是引用链接的数据，排序号可以在列表页修改，不需要提供编辑按钮

            _permissionChecker.IsMenuIdPermissionGrantedOrThrowException(menuId, LocalizationSource);

            var content = await _content2Repository.GetAsync(contentId);
            var menuContent = await _contentMenuRepository.FirstOrDefaultAsync(t => t.MenuId == menuId && t.RelateId == t.RelateId && t.ContentId == contentId);
            if(menuContent == null)
            {
                throw new UserFriendlyException("未找到该数据");
            }
            else if(menuContent.ManagementType != ManagementType.Manage)
            {
                throw new UserFriendlyException("没有编辑该数据的权限");
            }

            var oldOrder = content.Order;

            var bodyFields = await _contentBodyRepository.GetAllListAsync(c => c.ContentId == content.Id);
            var fields = await _contentFieldRepository.GetAllListAsync(c => c.ContentId == content.Id);

            customKey = await GetCustomKey(customKey, menuId);

            var config = await GetConfig(customKey, menuId);
            var bodyFields_New = new List<NameValue>();
            var fields_New = new List<NameValue>();
            Mapping(values, content, config, bodyFields_New, fields_New);

            if (content.PublishTime == 0)
            {
                content.PublishTime = Clock.Now.ToUnixTimeByMilliseconds();
            }
            var newOrder = content.Order;
            //内容表中保存了主栏目的栏目id和relateId(它们仅在创建和移动到其他栏目时修改)和它对应的排序号
            if (newOrder != oldOrder && (content.MenuId != menuId || content.RelateId != relateId))  
            {
                content.Order = oldOrder;
            }

            await _content2Repository.UpdateAsync(content);

            #region ContentBody

            // 1 原来没有的，要添加
            foreach (var item in bodyFields_New.Where(p => !bodyFields.Select(c => c.FieldName).Contains(p.Name)))
            {
                var body = new ContentBody { ContentId = content.Id, FieldName = item.Name, Value = item.Value };
                await _contentBodyRepository.InsertAsync(body);
            }
            foreach (var item in bodyFields)
            {
                // 原来有的而现在没有，要删掉; 其他修改
                var bodyField = bodyFields_New.FirstOrDefault(c => c.Name == item.FieldName);
                if (bodyField == null)
                {
                    await _contentBodyRepository.DeleteAsync(item);
                }
                else
                {
                    item.Value = bodyField.Value;
                }
            }
            #endregion

            #region ContentField

            // 1 原来没有的，要添加
            foreach (var item in fields_New.Where(p => !fields.Select(c => c.FieldName).Contains(p.Name)))
            {
                var body = new ContentField { ContentId = content.Id, FieldName = item.Name, Value = item.Value };
                await _contentFieldRepository.InsertAsync(body);
            }
            foreach (var item in fields)
            {
                // 原来有的而现在没有，要删掉; 其他修改
                var bodyField = fields_New.FirstOrDefault(c => c.Name == item.FieldName);
                if (bodyField == null)
                {
                    await _contentFieldRepository.DeleteAsync(item);
                }
                else
                {
                    item.Value = bodyField.Value;
                }
            }
            #endregion

            var menuList = await _contentMenuRepository.GetAllListAsync(t => t.ContentId == content.Id);
            foreach (var contentMenu in menuList)
            {
                long relateIdLong = 0;
                if (contentMenu.RelateId != null)
                {
                    relateIdLong = await GetAuxiliaryIdAsync(contentMenu.RelateId.Value);
                }

                if (MtSiteConsts2.BackgroundJobs)
                {
                    _staticPageHelper.DeleteListAndDetailPage(content.TenantId, content.Language, contentMenu.MenuId, content.AuxiliaryId, relateIdLong);
                }
                contentMenu.PublishTime = content.PublishTime;
                if(menuId == contentMenu.MenuId && relateId == contentMenu.RelateId)
                {
                    contentMenu.Order = newOrder;
                    await SetRouteStr(values, contentMenu.Id, menuId, relateIdLong, content, config, false);
                }
            }
            if (MtSiteConsts2.BackgroundJobs)
            {
                _staticPageHelper.DeleteStaticPage(content.TenantId, content.Language, 0);
            }

            await _dataLogsManager.CreateAsync(content, menuId, DataLogOptionType.Update);

            return content.Id;
        }

        private static void Mapping(Dictionary<string, string> values, Content2 content, ContentConfig config, List<NameValue> bodyFields_New, List<NameValue> fields_New)
        {
            var checker = new ContentDataChecher();
            Type type = content.GetType();
            var detailFields = config.Detail
                .Where(ContentFieldsHelper.CheckDataPredicate(_specialFields))
                .ToList();

            foreach (var item in values)
            {
                if (item.Key != "routeStr" && item.Key != "menuId")
                {
                    // 按values保存，但要验证合法性
                    var propertie = detailFields.FirstOrDefault(c => c.FieldName.ToCamelCase().Equals(item.Key));
                    if (propertie != null)
                    {
                        var propertieKey = propertie.FieldName.ToPascalCase();
                        var val = checker.Check(propertie.Security, item.Value, propertie.DisplayName, propertie.FieldType);
                        PropertyInfo property = type.GetProperty(propertieKey);
                        if (property != null && property.CanWrite)
                        {
                            TypeHelper.SetPropertyValue(content, propertieKey, val.ConvertTo(property.PropertyType));
                        }
                        else
                        {
                            if (propertie.FieldType == FieldType.Text)
                            {
                                if (val == null)
                                {
                                    bodyFields_New.Add(new NameValue(propertieKey, null));
                                }
                                else
                                {
                                    bodyFields_New.Add(new NameValue(propertieKey, val.ToString()));
                                }
                            }
                            else
                            {
                                if (val == null)
                                {
                                    fields_New.Add(new NameValue(propertieKey, null));
                                }
                                else
                                {
                                    fields_New.Add(new NameValue(propertieKey, val.ToString()));
                                }
                            }
                        }
                    }
                    else
                    {
                        if (item.Key == "order")
                        {
                            int order = 1;
                            int.TryParse(item.Value, out order);
                            content.Order = order;
                        }
                        if (item.Key == "autoSynchronous")
                        {
                            content.AutoSynchronous = item.Value != "false";
                        }
                    }
                }
            }
        }

        private async Task SetRouteStr(
            Dictionary<string, string> values, 
            Guid routeRelateId, long menuId, long relateIdLong, Content2 content, ContentConfig config, bool isCreating)
        {
            if (config.DiyRoute)
            {
                Guid? frontEndPageId = await _menuStore.GetDetailPageIdAsync(menuId);
                string routeStr = null;
                if (values.ContainsKey("routeStr"))
                {
                    routeStr = values["routeStr"];
                }

                // 20221111修改，为详情页自动生成链接
                if (routeStr.IsNullOrWhiteSpace())
                {
                    var menuItem = await _menuStore.GetMenuIdTraceCacheItemAsync(content.MenuId);
                    Guid menuGuid = menuItem.Id();
                    var listRouteStr = await _routeManager.GetRouteStrFromDbAsync(menuGuid, content.TenantId);
                    if(!listRouteStr.IsNullOrWhiteSpace())
                    {
                        var shortDataId = await _shortIdManager.GetShortIdAsync(content.AuxiliaryId);
                        routeStr = listRouteStr + "/" + shortDataId;
                    }
                }

                if (routeStr.IsNullOrEmpty())
                {
                    if (!isCreating)
                    {
                        await _routeManager.DeleteAsync(routeRelateId, content.TenantId);
                    }
                }
                else
                {
                    await _routeManager.CreateOrUpdateRouteStrAsync(
                        routeRelateId,
                        routeStr,
                        frontEndPageId/*可能是关联数据，而不是直接对应栏目*/,
                        menuId,
                        content.AuxiliaryId,
                        relateIdLong);
                }
            }
        }

        #region 列表页数据读取
        private async Task<Dictionary<Guid, int>> GetCountByContentIdListAsync(List<Guid> idList)
        {
            var query = from cm in _contentMenuRepository.GetAll()
                        where idList.Contains(cm.ContentId)
                        group cm by cm.ContentId into ng
                        select new
                        {
                            ng.Key,
                            Count = ng.Count()
                        };
            var data = await query.ToListAsync();
            return data.ToDictionary(t => t.Key, t => t.Count);
        }

        public async Task<PagedContent<Dictionary<string, object>>> GetContentListByPagedAsync(
            Func<IQueryable<Content2>, IQueryable<Content2>> queryMethod, int skipCount, int getCount, string customKey, long menuId, Guid? relateId)
        {
            var query = _content2Repository.GetAll().AsNoTracking().Where(t => t.TenantId == AbpSession.TenantId && t.Language == AbpSession.CultureName());
            query = queryMethod(query);

            var q = from cm in _contentMenuRepository.GetAll()
                    join c in query
                    on cm.ContentId equals c.Id
                    where cm.MenuId == menuId  && cm.RelateId == relateId
                    orderby cm.Order descending
                    select new Content2TempData
                    {
                        Content = c,
                        ContentMenu = cm
                    };

            int count;
            List<Content2TempData> list2;

            using (_unitOfWorkManager.Current.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage))
            {
                count = await q.CountAsync();
                list2 = await q.Skip(skipCount).Take(getCount).ToListAsync();
            }
            
            var dataMenuIds = await GetCountByContentIdListAsync(list2.Select(t => t.Content.Id).ToList());
            var dir = await TranlateAsConfig(list2, customKey, menuId, dataMenuIds, relateId);
           
            return new PagedContent<Dictionary<string, object>>
            {
                TotolCount = count,
                Items = dir,
                IsSingle = (count < 2)
            };
        }

        private async Task<List<Dictionary<string, object>>> TranlateAsConfig(List<Content2TempData> list, string customKey, long menuId, Dictionary<Guid, int> dataMenuIds, Guid? relateId)
        {
            var config = await GetConfig(customKey, menuId);
            var result = new List<Dictionary<string, object>>();
            if (config != null)
            {
                var listFields = config.List.Where(c => !string.IsNullOrEmpty(c.FieldName)).Select(c => c.FieldName.ToPascalCase()).ToList();
                foreach (var item2 in list)
                {
                    var item = item2.Content;
                    var dto = new Dictionary<string, object>();
                    foreach (var propertieKey in listFields)
                    {
                        var value = TypeHelper.GetPropertyValue(item, propertieKey);
                        dto.Add(propertieKey.ToCamelCase(), value);
                    }
                    dto["id"] = item.Id;
                    dto["auxiliaryId"] = item.AuxiliaryId;
                    dto["menuId"] = item.MenuId;
                    dto["key"] = item.Key;
                    dto["order"] = item2.ContentMenu.Order;
                    dto["managementType"] = item2.ContentMenu.ManagementType;
                    dto["menuCount"] = dataMenuIds.ContainsKey(item.Id) ? dataMenuIds[item.Id] : 0;
                    dto["relateId"] = relateId;
                    dto["creationTime"] = item.CreationTime.ToUnixTimeByMilliseconds();
                    dto["lastModificationTime"] = item.LastModificationTime == null ? 0 : (item.LastModificationTime.Value.ToUnixTimeByMilliseconds());

                    result.Add(dto);
                }
            }

            return result;
        }

        #endregion

        public List<string> GetSpecialFields()
        {
            return _specialFields.Select(c => c.ToCamelCase()).ToList();
        }

        #region --

        public async Task DeleteAysnc(Guid id, long menuId, Guid? relateId)
        {
            var entity = _content2Repository.FirstOrDefault(id);
            if (entity == null 
                || !_permissionChecker.IsGranted(MenuPermissions.Pages_Tenant_Menu_Content, menuId))
            {
                return;
            }

            var config = await GetConfig(entity.Key, entity.MenuId);

            var menuList = await _contentMenuRepository.GetAllListAsync(t => t.ContentId == id);
            var otherManageMenus = menuList
                .Where(t => (t.MenuId != menuId || t.RelateId != relateId) && t.ManagementType == ManagementType.Manage)
                .OrderBy(t=>t.CreationTime);
            var otherManageMenu = otherManageMenus.FirstOrDefault(t => t.RelateId == null);
            if (otherManageMenu == null)
            {
                otherManageMenu = otherManageMenus.FirstOrDefault();
            }
            if (otherManageMenu == null)
            {
                //删数据，删所有相关栏目的静态页
                foreach (var menu in menuList)
                {
                    if (MtSiteConsts2.BackgroundJobs)
                    {
                        _staticPageHelper.DeleteListAndDetailPage(entity.TenantId, entity.Language, menu.MenuId, entity.AuxiliaryId);
                    }

                    await _routeManager.DeleteAsync(menu.Id, entity.TenantId);
                    await _contentMenuRepository.DeleteAsync(menu);
                }
                if (MtSiteConsts2.BackgroundJobs)
                {
                    _staticPageHelper.DeleteStaticPage(entity.TenantId, entity.Language, 0);
                }

                await _seoRepository.DeleteAsync(item => item.RelatedId == id);
                await _fileObjectManager.DeleteListByContentId(id);
                await _content2Repository.DeleteAsync(id);
                await _dataLogsManager.CreateAsync(entity, menuId, DataLogOptionType.Delete);
            }
            else
            {
                //删关系
                var menu = menuList.FirstOrDefault(t => t.MenuId == menuId && t.RelateId == relateId);
                if (menu != null)
                {
                    if (MtSiteConsts2.BackgroundJobs)
                    {
                        _staticPageHelper.DeleteListAndDetailPage(entity.TenantId, entity.Language, menuId, entity.AuxiliaryId);
                        _staticPageHelper.DeleteStaticPage(entity.TenantId, entity.Language, 0);
                    }
                    await _routeManager.DeleteAsync(menu.Id, entity.TenantId);

                    await _contentMenuRepository.DeleteAsync(menu);

                    if (entity.MenuId == menuId && entity.RelateId == relateId)
                    {
                        entity.MenuId = otherManageMenu.MenuId;
                        entity.RelateId = otherManageMenu.RelateId;
                    }

                    await _dataLogsManager.CreateAsync(entity, menuId, DataLogOptionType.Delete);
                }
            }
        }

        public async Task DeleteListAysnc(IList<Guid> idList, long menuId, Guid? relateId)
        {
            foreach (var item in idList)
            {
                await DeleteAysnc(item, menuId, relateId);
            }
        }

        public async Task SetNewOrderNumberAsync(Guid id, long menuId, int order, Guid? relateId)
        {
            var entity = await _content2Repository.GetAsync(id);
            if(entity == null)
            {
                return;
            }

            var menu = await _contentMenuRepository.FirstOrDefaultAsync(t => t.ContentId == id && t.MenuId == menuId && t.RelateId == relateId);
            if(menu != null)
            {
                menu.Order = order;
                if(entity.MenuId == menuId && entity.RelateId == relateId)
                {
                    entity.Order = order;
                }

                if (MtSiteConsts2.BackgroundJobs)
                {
                    _staticPageHelper.DeleteListPage(entity.TenantId, entity.Language, entity.MenuId);
                    _staticPageHelper.DeleteStaticPage(entity.TenantId, entity.Language, 0);
                }
            }
        }

        public async Task SetStatus(IList<Guid> idList, long menuId, bool isActive)
        {
            var list = await _content2Repository.GetAllListAsync(c => idList.Contains(c.Id));
            if(list.Count == 0)
            {
                return;
            }

            //ContentConfig config = await GetConfig(list[0].Key, menuId);

            foreach (var item in list)
            {
                var menuList = await _contentMenuRepository.GetAllListAsync(t => t.ContentId == item.Id);
                foreach (var menu in menuList)
                {
                    if (MtSiteConsts2.BackgroundJobs)
                    {
                        if (isActive)
                        {
                            _staticPageHelper.DeleteListPage(item.TenantId, item.Language, menu.MenuId);
                        }
                        else
                        {
                            _staticPageHelper.DeleteListAndDetailPage(item.TenantId, item.Language, menu.MenuId, item.AuxiliaryId);
                        }
                    }
                }

                item.IsActive = isActive;

                await _dataLogsManager.CreateAsync(item, menuId, item.IsActive ? DataLogOptionType.Publish : DataLogOptionType.UnPublish);
            }

            if (MtSiteConsts2.BackgroundJobs)
            {
                _staticPageHelper.DeleteStaticPage(list[0].TenantId, list[0].Language, 0);
            }
        }

        public async Task SwapObjectSortAsync(List<Guid> idList, long menuId, List<int> orderList, Guid? relateId)
        {
            var list = await _content2Repository.GetAllListAsync(c => idList.Contains(c.Id));
            if (list.Count == 0)
            {
                return;
            }

            //ContentConfig config = await GetConfig(list[0].Key, menuId);
            var menuList = await _contentMenuRepository.GetAllListAsync(t => idList.Contains(t.ContentId) && t.MenuId == menuId && t.RelateId == relateId);

            foreach (var item in list)
            {
                var index = idList.FindIndex(c => c == item.Id);
                if (index != -1)
                {
                    var menu = menuList.FirstOrDefault(t => t.ContentId == item.Id);
                    if (menu != null)
                    {
                        menu.Order = orderList[index];
                        if(item.MenuId == menuId && item.RelateId == relateId)
                        {
                            item.Order = orderList[index];
                        }
                    }
                }

                if (MtSiteConsts2.BackgroundJobs)
                {
                    _staticPageHelper.DeleteListPage(item.TenantId, item.Language, menuId);
                }
            }

            if (MtSiteConsts2.BackgroundJobs)
            {
                _staticPageHelper.DeleteStaticPage(list[0].TenantId, list[0].Language, 0);
            }
        }
        #endregion

        //public async Task RecoverContentAsync(List<Guid> idList)
        //{
        //    if (idList.Count > 0)
        //    {
        //        using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
        //        {
        //            var contentList = await _contentRepository.GetAllListAsync(item => idList.Contains(item.Id));

        //            foreach (var item in contentList)
        //            {
        //                item.IsDeleted = false;
        //                await _contentRepository.UpdateAsync(item);

        //                await _dataLogsManager.CreateAsync(item, DataLogOptionType.UnDelete);
        //            }
        //        }
        //    }
        //}
    
    
        public async Task MoveToAnotherMenuAsync(Guid id, long fromMenuId, Guid? fromRelateId, long toMenuId, Guid? toRelateId)
        {
            var entity = _content2Repository.FirstOrDefault(id);
            if (entity == null)
            {
                return;
            }

            if (entity.MenuId != fromMenuId || entity.RelateId != fromRelateId)
            {
                return;
            }

            // 确认那边是否已有
            var menuList = await _contentMenuRepository.GetAllListAsync(t => t.ContentId == id);
            if (menuList.FirstOrDefault(t => t.MenuId == toMenuId && t.RelateId == toRelateId) != null)
            {
                return;
            }

            var fromMenu = menuList.FirstOrDefault(t => t.MenuId == fromMenuId && t.RelateId == fromRelateId);
            if(fromMenu == null)
            {
                return;
            }

            fromMenu.MenuId = toMenuId;
            fromMenu.RelateId = toRelateId; 
            fromMenu.Order = await GetMaxOrderNumber(toMenuId, toRelateId);
            entity.MenuId = toMenuId;
            entity.RelateId = toRelateId;

            if (MtSiteConsts2.BackgroundJobs)
            {
                //ContentConfig config = await GetConfig(entity.Key, fromMenuId);
                _staticPageHelper.DeleteListAndDetailPage(entity.TenantId, entity.Language, fromMenuId, entity.AuxiliaryId);
                _staticPageHelper.DeleteListPage(entity.TenantId, entity.Language, toMenuId);
                _staticPageHelper.DeleteStaticPage(entity.TenantId, entity.Language, 0);
                await _routeManager.DeleteAsync(fromMenu.Id, entity.TenantId);
            }

            await _dataLogsManager.CreateAsync(entity, fromMenuId, DataLogOptionType.MoveToOtherMenu);
        }

        public async Task CopyToOtherMenuAsync(Guid id, long fromMenuId, Guid? fromRelateId, long toMenuId, Guid? toRelateId)
        {
            var entity = _content2Repository.FirstOrDefault(id);
            if (entity == null)
            {
                return;
            }

            if (entity.MenuId != fromMenuId || entity.RelateId != fromRelateId)
            {
                return;
            }

            // 确认那边是否已有
            var fromMenu = await _contentMenuRepository.FirstOrDefaultAsync(t => t.ContentId == id && t.MenuId == fromMenuId && t.RelateId == fromRelateId);
            if (fromMenu == null)
            {
                return;
            }

            var bodyFields = await _contentBodyRepository.GetAllListAsync(c => c.ContentId == entity.Id);
            var fields = await _contentFieldRepository.GetAllListAsync(c => c.ContentId == entity.Id);

            var newOrder = await GetMaxOrderNumber(toMenuId, toRelateId);
            // 复制
            var newContent = new Content2
            {
                Id = Guid.NewGuid(),
                MenuId = toMenuId,
                RelateId = toRelateId,
                Title = entity.Title,
                Body = entity.Body,
                Body2 = entity.Body2,
                Key = entity.Key,
                Hit = 0,
                Order = newOrder,
                Time1 = entity.Time1,
                Time2 = entity.Time2,
                Time3 = entity.Time3,
                Time4 = entity.Time4,
                Str1 = entity.Str1,
                Str2 = entity.Str2,
                Str3 = entity.Str3,
                Str4 = entity.Str4,
                Str5 = entity.Str5,
                Str6 = entity.Str6,
                Str7 = entity.Str7,
                Str8 = entity.Str8,
                Str9 = entity.Str9,
                Str10 = entity.Str10,
                Str11 = entity.Str11,
                Str12 = entity.Str12,
                Str13 = entity.Str13,
                Str14 = entity.Str14,
                Str15 = entity.Str15,
                Bool1 = entity.Bool1,
                Bool2 = entity.Bool2,
                Bool3 = entity.Bool3,
                Bool4 = entity.Bool4,
                Int1 = entity.Int1,
                Int2 = entity.Int2,
                Int3 = entity.Int3,
                Int4 = entity.Int4,
                Double1 = entity.Double1,
                Double2 = entity.Double2,
                Double3 = entity.Double3,
                Double4 = entity.Double4,
                AutoSynchronous = entity.AutoSynchronous,
                PublishTime = entity.PublishTime
            };
            await _content2Repository.InsertAsync(newContent);

            foreach (var item in bodyFields)
            {
                var body = new ContentBody { ContentId = newContent.Id, FieldName = item.FieldName, Value = item.Value };
                await _contentBodyRepository.InsertAsync(body);
            }
            foreach (var item in fields)
            {
                var body = new ContentField { ContentId = newContent.Id, FieldName = item.FieldName, Value = item.Value };
                await _contentFieldRepository.InsertAsync(body);
            }

            var contentMenuId = Guid.NewGuid();
            await _contentMenuRepository.InsertAsync(new ContentMenu
            {
                Id = contentMenuId,
                MenuId = toMenuId,
                RelateId = toRelateId,
                ContentId = newContent.Id,
                EntityTypeName = newContent.GetType().Name,
                ManagementType = fromMenu.ManagementType,
                Order = newOrder,
                PublishTime = entity.PublishTime
            });

            // 附件
            await _fileObjectManager.CopyAllFileObject(id, newContent.Id);

            if (MtSiteConsts2.BackgroundJobs)
            {
                //ContentConfig config = await GetConfig(entity.Key, fromMenuId);
                _staticPageHelper.DeleteListPage(entity.TenantId, entity.Language, toMenuId);
                _staticPageHelper.DeleteStaticPage(entity.TenantId, entity.Language, 0);
            }

            await _dataLogsManager.CreateAsync(entity, fromMenuId, DataLogOptionType.CopyToOtherMenu);
        }

        public async Task ShareToOtherMenuAsync(Guid id, long fromMenuId, Guid? fromRelateId, long toMenuId, Guid? toRelateId, ManagementType managementType)
        {
            if (toMenuId == fromMenuId && toRelateId == fromRelateId)
            {
                return;
            }

            var entity = _content2Repository.FirstOrDefault(id);
            if (entity == null)
            {
                return;
            }

            if (entity.MenuId != fromMenuId || entity.RelateId != fromRelateId)
            {
                return;
            }

            var menuList = await _contentMenuRepository.GetAllListAsync(t => t.ContentId == id);
            var menu = menuList.FirstOrDefault(t => t.MenuId == fromMenuId && t.RelateId == fromRelateId);
            if (menu == null)
            {
                return;
            }

            // 确认那边是否已有
            if (menuList.FirstOrDefault(t => t.MenuId == toMenuId && t.RelateId == toRelateId) != null)
            {
                return;
            }

            ContentConfig toMenuConfig = await _menuContentHelper.GetConfig(null, toMenuId);
            if(toMenuConfig == null)
            {
                // 非内容
                return;
            }

            if (!_permissionChecker.IsGranted(ContentPermissions.Pages_Manage_Content_Create, toMenuId))
            {
                return;
            }

            var newOrder = await GetMaxOrderNumber(toMenuId, toRelateId);
            var contentMenuId = Guid.NewGuid();
            await _contentMenuRepository.InsertAsync(new ContentMenu
            {
                Id = contentMenuId,
                MenuId = toMenuId,
                RelateId = toRelateId,
                ContentId = id,
                EntityTypeName = entity.GetType().Name,
                ManagementType = managementType,
                Order = newOrder,
                PublishTime = entity.PublishTime
            });

            if (MtSiteConsts2.BackgroundJobs)
            {
                _staticPageHelper.DeleteListPage(entity.TenantId, entity.Language, toMenuId);
                _staticPageHelper.DeleteStaticPage(entity.TenantId, entity.Language, 0);
            }

            await _dataLogsManager.CreateAsync(entity, fromMenuId, DataLogOptionType.ShareToOtherMenu);
        }

        // 补充专题的数据信息
        public async Task<SharedInfoOutput> GetSharedInfoAsync(Guid id, long menuId, Guid? relateId)
        {
            var list = await GetAllSharedInfoAsync(id);

            var query2 = from c in _content2Repository.GetAll()
                                where c.Id == id
                                select new
                                {
                                    c.MenuId,
                                    c.RelateId
                                };
            var currentMenu = await query2.FirstOrDefaultAsync();

            var result = new SharedInfoOutput();
            var data = list.FirstOrDefault(c => c.MenuId == menuId && c.RelateId == relateId);
            if(data != null)
            {    
                //当前栏目是否是源数据所在
                result.Type = (data.MenuId == currentMenu.MenuId && data.RelateId == currentMenu.RelateId);

                var items = new List<NameValue<ManagementType>>();

                if (result.Type)
                {
                    foreach (var item in list.Where(c => c.MenuId != currentMenu.MenuId || c.RelateId != currentMenu.RelateId))
                    {
                        var menuItem = await _menuStore.GetMenuIdTraceCacheItemAsync(item.MenuId);
                        var path = await _menuContentHelper.GetMenuPathAsync(menuItem);
                        if (item.RelateId == null)
                        {
                            items.Add(new NameValue<ManagementType>(path.JoinAsString(" / "), item.ManagementType));
                        }
                        else
                        {
                            //查找关联数据的标题
                            path.Add(await GetTitleAsync(item.RelateId.Value));
                            items.Add(new NameValue<ManagementType>(path.JoinAsString(" / "), item.ManagementType));
                        }
                    }
                    result.Items = items;
                    return result;

                }
                else
                {
                    var data2 = list.FirstOrDefault(c => c.MenuId == currentMenu.MenuId && c.RelateId == currentMenu.RelateId);
                    if (data2 != null)
                    {
                        var menuItem = await _menuStore.GetMenuIdTraceCacheItemAsync(data2.MenuId);
                        var path = await _menuContentHelper.GetMenuPathAsync(menuItem);
                        if (data2.RelateId == null)
                        {
                            items.Add(new NameValue<ManagementType>(path.JoinAsString(" / "), data2.ManagementType));
                        }
                        else
                        {
                            //查找关联数据的标题
                            path.Add(await GetTitleAsync(data2.RelateId.Value));
                            items.Add(new NameValue<ManagementType>(path.JoinAsString(" / "), data2.ManagementType));
                        }
                        result.Items = items;
                        return result;
                    }
                }
            }

            result.Items = new List<NameValue<ManagementType>>();
            return result;
        }

        private async Task<string> GetTitleAsync(Guid id)
        {
            var q = from c in _contentRepository.GetAll()
                    where c.Id == id
                    select c.Title;

            return await q.FirstOrDefaultAsync();
        }
        private async Task<long> GetAuxiliaryIdAsync(Guid id)
        {
            var q = from c in _contentRepository.GetAll()
                    where c.Id == id
                    select c.AuxiliaryId;

            return await q.FirstOrDefaultAsync();
        }

        // 专题是难以主动从其他栏目推送过来的，简单的实现方式是改为由专题的新闻列表页主动拉取, 但这样存在死角，无法从一个专题的列表分享到另一个专题的列表
        //   主动选择专题栏目去推送的实现方式：  拉取所有专题栏目 ->  分页加载专题数据 ->  选择专题数据-> 选择目标新闻列表
        //     内容模块的不足： 1.  控件的需要更多选择，更好的可扩展性（支持自定义控件）  2. 关联数据 需要能支持多列
        public async Task<AllMenusForOperation> GetAllMenusForTopicOperationAsync(string customKey, string customKey2)
        {
            if (customKey.IsNullOrEmpty())
            {
                // 取所有内容配置，从中遍历找出
                var allContentDef = await _menuContentHelper.CustomConfigManager.GetAllConfigByTypeAsync("ContentDefinition");

                var menuList = new List<MenuSampeInfo>();
                foreach (var contentDef in allContentDef)
                {
                    var config = contentDef.Value.FromJsonString<ContentConfig>();
                    if(config != null && config.List != null)
                    {
                        var relateItem = config.List.FirstOrDefault(t => t.FieldName.IsNullOrEmpty() && t.ContentType == "content2");
                        if (relateItem != null && relateItem.RelateDataKey == customKey2)
                        {
                            var menus = await _menuContentHelper.GetAllMenusByCustomKeyAsync(contentDef.Name, ContentPermissionProvider.ModuleName);
                            menuList.AddRange(menus);
                        }
                    }
                }

                return new AllMenusForOperation
                {
                    Items = menuList //.Where(t => _permissionChecker.IsGranted(ContentPermissions.Pages_Manage_Content_Create, t.Id)).ToList()
                };
            }
            else
            {
                var config = await _menuContentHelper.GetConfig(customKey);
                if (config != null && config.List != null)
                {
                    var relateItem = config.List.FirstOrDefault(t => t.FieldName.IsNullOrEmpty() && t.ContentType == "content2");
                    if (relateItem != null && relateItem.RelateDataKey == customKey2)
                    {
                        var menus = await _menuContentHelper.GetAllMenusByCustomKeyAsync(customKey, ContentPermissionProvider.ModuleName);
                        return new AllMenusForOperation
                        {
                            Items = menus //.Where(t => _permissionChecker.IsGranted(ContentPermissions.Pages_Manage_Content_Create, t.Id)).ToList()
                        };
                    }
                }
            }

            return new AllMenusForOperation
            {
                Items = new List<MenuSampeInfo>()
            };
        }
        
        public async Task<AllMenusForOperation> GetAllMenusForOperationAsync(
            string customKey, Guid id, ContentOperationType operationType, long currentMenu) 
        {
            // 1. 找出所有同配置的栏目
            //1. 移动（剔除本栏目）or复制，2. 共享（剔除本栏目和已共享的栏目）

            var result = await _menuContentHelper.GetAllMenusByCustomKeyAsync(customKey, ContentPermissionProvider.ModuleName2);

            if(operationType == ContentOperationType.Move)
            {
                result = result.Where(t => t.AuxiliaryId != currentMenu).ToList();
            }

            if(operationType == ContentOperationType.Share)
            {
                ContentConfig config = await _menuContentHelper.GetConfig(customKey);
                if (!config.ShareToCustomKeyList.IsNullOrEmpty())
                {
                    foreach (var item in config.ShareToCustomKeyList.Where(t => t != customKey))
                    {
                        var otherMenus = await _menuContentHelper.GetAllMenusByCustomKeyAsync(item, ContentPermissionProvider.ModuleName2);
                        foreach (var newMenu in otherMenus)
                        {
                            if(result.FirstOrDefault(t=> t.Id == newMenu.Id) == null)
                            {
                                result.Add(newMenu);
                            }
                        }
                    }
                }

                var sharedData = await GetAllSharedInfoAsync(id);
                var allMenuIds = sharedData.Select(c => c.MenuId);
                result = result.Where(t => !allMenuIds.Contains(t.AuxiliaryId)).ToList();
            }

            return new AllMenusForOperation { Items = result };
        }
        public async Task<AllMenusForOperation> GetAllMenusAsync(string customKey)
        {
            var result = await _menuContentHelper.GetAllMenusByCustomKeyAsync(customKey, ContentPermissionProvider.ModuleName2);
            return new AllMenusForOperation { Items = result };
        }

        private async Task<List<ContentMenu>> GetAllSharedInfoAsync(Guid id)
        {
            var query = from cm in _contentMenuRepository.GetAll()
                        where cm.ContentId == id
                        select cm;
            return await query.ToListAsync();
        }


        private async Task<int> GetMaxOrderNumber(long menuId, Guid? relateId)
        {
            var query = from q in _contentMenuRepository.GetAll()
                        where q.MenuId == menuId && q.RelateId == relateId
                        orderby q.Order descending
                        select q;
            var m = await query.FirstOrDefaultAsync();
            if (m != null)
            {
                return m.Order + 1;
            }
            else
            {
                return 1;
            }
        }
    }
}
